package com.idealighter.game.games.blackjack.struct;

import java.util.ArrayList;
import java.util.List;


/**
 * 黑杰克获取牌型 .
 *
 * @ClassName . BlackjackCardsTypeGetter.
 * @author abin
 * @date 2018年3月19日 下午4:58:11 .
 */
public class BlackjackCardsTypeGetter {

  private static final int POINT = 21;

  private static final int FIVE_DRAGON_CARDS_NUM = 5;

  private static final int BANKER_MIN_POINT = 17; // 庄家最少点数

  public static final List<BlackjackCardsTypeAndPoint> BANKER_CARD_TYPES;

  static {
    BANKER_CARD_TYPES = new ArrayList<>();

    BlackjackCardsTypeAndPoint bust = new BlackjackCardsTypeAndPoint(BlackjackCardsType.BUST, 0);
    BANKER_CARD_TYPES.add(bust);

    BlackjackCardsTypeAndPoint normal17 =
        new BlackjackCardsTypeAndPoint(BlackjackCardsType.NORMAL, 17);
    BANKER_CARD_TYPES.add(normal17);

    BlackjackCardsTypeAndPoint normal18 =
        new BlackjackCardsTypeAndPoint(BlackjackCardsType.NORMAL, 18);
    BANKER_CARD_TYPES.add(normal18);

    BlackjackCardsTypeAndPoint normal19 =
        new BlackjackCardsTypeAndPoint(BlackjackCardsType.NORMAL, 19);
    BANKER_CARD_TYPES.add(normal19);

    BlackjackCardsTypeAndPoint normal20 =
        new BlackjackCardsTypeAndPoint(BlackjackCardsType.NORMAL, 20);
    BANKER_CARD_TYPES.add(normal20);

    BlackjackCardsTypeAndPoint normal21 =
        new BlackjackCardsTypeAndPoint(BlackjackCardsType.NORMAL, 21);
    BANKER_CARD_TYPES.add(normal21);

    // 黑杰克的控制应该在游戏开始.

    // BlackjackCardsTypeAndPoint blackjack =
    // new BlackjackCardsTypeAndPoint(BlackjackCardsType.BLACK_JACK, 0);
    // BANKER_CARD_TYPES.add(blackjack);


    BlackjackCardsTypeAndPoint fiveDragon =
        new BlackjackCardsTypeAndPoint(BlackjackCardsType.FIVE_DRAGON, 0);
    BANKER_CARD_TYPES.add(fiveDragon);

  }

  private BlackjackCardsTypeGetter() {}

  /**
   * 获取牌组.
   * 
   * @param cards 数组列表.
   * @return 结果.
   */
  public static BlackjackCardsTypeAndPoint getCardsType(List<BlackjackCard> cards,
      boolean isSplit) {

    int point = getLessNear21Point(cards);
    BlackjackCardsType cardsType = BlackjackCardsType.NORMAL;
    if (isBlackJack(cards, point, isSplit)) {
      cardsType = BlackjackCardsType.BLACK_JACK;
      point = 0;
    } else if (isFiveDragon(cards, point)) {
      cardsType = BlackjackCardsType.FIVE_DRAGON;
      point = 0;
    } else if (isBust(point)) {
      cardsType = BlackjackCardsType.BUST;
      point = 0;
    }
    BlackjackCardsTypeAndPoint cardAndPoint = new BlackjackCardsTypeAndPoint(cardsType, point);

    return cardAndPoint;
  }

  /**
   * 从卡的点数，获取卡牌信息 .
   *
   * @author abin
   * @date 2018年3月31日 下午2:16:15
   * @param powers 卡牌数组.
   * @return 结果.
   */
  public static BlackjackCardsTypeAndPoint getCardsTypeByPower(List<Integer> powers) {
    int point = getLessNear21PointByPower(powers);
    BlackjackCardsType cardsType = BlackjackCardsType.NORMAL;
    if (isBlackJackByPower(powers, point)) {
      cardsType = BlackjackCardsType.BLACK_JACK;
      point = 0;
    } else if (isFiveDragonByPower(powers, point)) {
      cardsType = BlackjackCardsType.FIVE_DRAGON;
      point = 0;
    } else if (isBust(point)) {
      cardsType = BlackjackCardsType.BUST;
      point = 0;
    }
    BlackjackCardsTypeAndPoint cardAndPoint = new BlackjackCardsTypeAndPoint(cardsType, point);

    return cardAndPoint;
  }


  /**
   * 是不是五龙 .
   *
   * @Title isFiveDragon.
   * @author abin
   * @date 2018年3月19日 下午5:02:28
   * @param cards 牌组.
   * @return 结果.
   */
  public static boolean isFiveDragon(List<BlackjackCard> cards, int point) {
    return cards != null && !cards.isEmpty() && cards.size() == FIVE_DRAGON_CARDS_NUM
        && point <= POINT;
  }

  /**
   * 是否五龙.
   *
   * @author abin
   * @date 2018年3月31日 下午2:15:42
   * @param powers 卡牌数组.
   * @param point 点数.
   * @return 结果.
   */
  public static boolean isFiveDragonByPower(List<Integer> powers, int point) {
    return powers != null && !powers.isEmpty() && powers.size() == FIVE_DRAGON_CARDS_NUM
        && point <= POINT;
  }


  /**
   * 是否黑杰克.
   *
   * @Title isBlackJack.
   * @author abin
   * @date 2018年3月19日 下午5:03:21
   * @param cards 牌组.
   * @return 结果.
   */
  public static boolean isBlackJack(List<BlackjackCard> cards, int point, boolean isSplit) {
    boolean hasA = false;
    boolean hasTen = false;
    if (!isSplit && cards.size() == 2 && point == POINT) {
      for (BlackjackCard card : cards) {
        if (card.getPower() == BlackjackCard.HEI_TAO_A.getPower()) {
          hasA = true;
        } else if (card.getPower() >= BlackjackCard.HEI_TAO_SHI.getPower()) {
          hasTen = true;
        }
      }
    }

    boolean result = false;
    if (hasA && hasTen) {
      result = true;
    }
    return result;
  }

  private static boolean isBlackJackByPower(List<Integer> powers, int point) {
    boolean hasA = false;
    boolean hasTen = false;
    if (powers.size() == 2 && point == POINT) {
      for (Integer power : powers) {
        if (power == BlackjackCard.HEI_TAO_A.getPower()) {
          hasA = true;
        } else if (power >= BlackjackCard.HEI_TAO_SHI.getPower()) {
          hasTen = true;
        }
      }
    }

    boolean result = false;
    if (hasA && hasTen) {
      result = true;
    }
    return result;
  }


  /**
   * 是否爆牌 .
   *
   * @Title isBust.
   * @author abin
   * @date 2018年3月19日 下午7:28:21
   * @param point 点数.
   * @return 结果.
   */
  public static boolean isBust(int point) {
    return point > POINT;
  }

  private static boolean canOp(BlackjackCardsType cardsType) {
    return cardsType.equals(BlackjackCardsType.NORMAL);
  }

  /**
   * 是否可以双倍 .
   *
   * @author abin
   * @date 2018年3月27日 上午11:21:49
   * @param cards 牌组.
   * @param cardsType 牌组类型.
   * @return 结果.
   */
  public static boolean canDoubleDown(List<BlackjackCard> cards, BlackjackCardsType cardsType) {
    return canOp(cardsType) && cards.size() == 2;
  }

  /**
   * 是否可以分牌 .
   *
   * @author abin
   * @date 2018年3月27日 上午11:24:25
   * @param cards 牌组.
   * @return 结果.
   */
  public static boolean canSplit(List<BlackjackCard> cards, BlackjackCardsType cardsType) {
    return canOp(cardsType) && cards.size() == 2
        && cards.get(0).getPower() == cards.get(1).getPower();
  }

  /**
   * 是否可以补牌 .
   *
   * @author abin
   * @date 2018年3月27日 上午11:26:48
   * @param cardsType 牌组类型.
   * @return 结果.
   */
  public static boolean canHit(BlackjackCardsType cardsType) {
    return canOp(cardsType);
  }

  /**
   * 庄家是否可以补牌 .
   *
   * @author abin
   * @date 2018年3月28日 下午1:50:01
   * @param cardsTypeAndPoint 牌型.
   * @return 结果.
   */
  public static boolean bankCanHit(BlackjackCardsTypeAndPoint cardsTypeAndPoint) {
    return canOp(cardsTypeAndPoint.getCardsType())
        && cardsTypeAndPoint.getPoint() < BANKER_MIN_POINT;
  }

  /**
   * 是否可以停牌 .
   *
   * @author abin
   * @date 2018年3月27日 上午11:27:28
   * @param cardsType 牌组类型.
   * @return 结果.
   */
  public static boolean canStand(BlackjackCardsType cardsType) {
    return canOp(cardsType);
  }

  public static int MULTIPLE_RATE = 10;

  /**
   * 是否翻倍 .
   *
   * @author abin
   * @date 2018年3月28日 下午3:08:51
   * @param cardsType 类型.
   * @return 结果.
   */
  public static int multipleCheck(BlackjackCardsType cardsType) {
    int multiple = 0;
    if (cardsType.equals(BlackjackCardsType.BLACK_JACK)) {
      multiple = 25;
    } else if (cardsType.equals(BlackjackCardsType.FIVE_DRAGON)) {
      multiple = 30;
    } else {
      multiple = 20;
    }

    return multiple;
  }


  /**
   * 获取卡牌点数(当包含A，则处理替换判定是否最接近) .
   *
   * @Title getLessNear21Point.
   * @author abin
   * @date 2018年3月19日 下午7:56:58
   * @param cards 牌组.
   * @return 最接近21点的点数.
   */
  private static int getLessNear21Point(List<BlackjackCard> cards) {
    int point = 0;
    int atimes = 0;
    for (BlackjackCard blackjackCard : cards) {
      if (blackjackCard.getPower() == BlackjackCard.HEI_TAO_A.getPower()) {
        atimes++;
      }
      point += blackjackCard.getNum();
    }
    int finalPoint = point;
    while (point <= POINT && atimes > 0) {
      finalPoint = point;
      point += 10;
      atimes--;
    }
    if (point <= POINT) {
      finalPoint = point;
    }


    return finalPoint;

  }



  /**
   * 最解决21点的点数 .
   *
   * @author abin
   * @date 2018年3月31日 下午2:14:14
   * @param cards 卡牌组.
   * @return 点数.
   */
  private static int getLessNear21PointByPower(List<Integer> powers) {
    int point = 0;
    int atimes = 0;
    for (Integer power : powers) {
      if (power == BlackjackCard.HEI_TAO_A.getPower()) {
        atimes++;
      }
      if (power >= BlackjackCard.HEI_TAO_SHI.getPower()) {
        point += BlackjackCard.HEI_TAO_SHI.getNum();
      } else {
        point += power;
      }

    }
    int finalPoint = point;
    while (point <= POINT && atimes > 0) {
      finalPoint = point;
      point += 10;
      atimes--;
    }

    if (point <= POINT) {
      finalPoint = point;
    }

    return finalPoint;
  }

}
